﻿// *----------------------------------------------------------------
// Copyright (C) 2017 通通优品
// 版权所有。
// 
// 类名：ModuleManager.cs
// 功能描述：TongTongMall
// 
// Create User：jym 2017/02/09
// 
// Edit User：UserName,EditTime
// Describe：Describe
// ----------------------------------------------------------------*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using TongTongMall.Dependecy;
using TongTongMall.Collections.Extensions;
using Castle.Core.Logging;
using TongTongMall.Configuration.Startup;

namespace TongTongMall.Modules
{
    public class ModuleManager : IModuleManager
    {
        public ILogger Logger { get; set; }

        private readonly ModuleCollection _modules;

        private readonly IIocManager _iocManager;
        private readonly IModuleFinder _moduleFinder;


        public ModuleManager(IIocManager iocManager, IModuleFinder moduleFinder)
        {
            _modules = new ModuleCollection();
            _iocManager = iocManager;
            _moduleFinder = moduleFinder;
            Logger = NullLogger.Instance;
        }
        /// <summary>
        /// 初始化各个功能模块
        /// </summary>
        public void InitializeModules()
        {
            LoadAll();

            var sortedModules = _modules.GetSortedModuleListByDependency();

            sortedModules.ForEach(module => module.Instance.PreInitialize());
            sortedModules.ForEach(module => module.Instance.Initialize());
            sortedModules.ForEach(module => module.Instance.PostInitialize());
        }

        /// <summary>
        /// 释放时执行
        /// </summary>
        public void ShutdownModules()
        {
            var sortedModules = _modules.GetSortedModuleListByDependency();
            sortedModules.Reverse();
            sortedModules.ForEach(sm => sm.Instance.Shutdown());
        }

        private void LoadAll()
        {
            Logger.Debug("开始加载程序集模块");
            var moduleTypes = AddMissingDependedModules(_moduleFinder.FindAll());
            Logger.Debug("当前程序集的个数为：" + moduleTypes.Count );
            foreach (var moduleType in moduleTypes)
            {
                if (!BaseModule.IsBaseModule(moduleType))
                {
                    throw new TongTongMallException("此程序集不是有效的BaseModule类型: " + moduleType.AssemblyQualifiedName);
                }

                if (!_iocManager.IsRegistered(moduleType))
                {
                    _iocManager.Register(moduleType);
                }
            }
            foreach (var moduleType in moduleTypes)
            {
                var moduleObject = (BaseModule)_iocManager.IocContainer.Resolve(moduleType);

                moduleObject.IocManager = _iocManager;
                moduleObject.Configuration = _iocManager.Resolve<IStartupConfiguration>();

                _modules.Add(new ModuleInfo(moduleObject));

                Logger.DebugFormat("加载模块: " + moduleType.AssemblyQualifiedName);
            }

            //首先需要加载加载核心类库方法
            EnsureKernelModuleToBeFirst(_modules);

            SetDependencies();

            Logger.DebugFormat("{0} 个模块被加载.", _modules.Count);
        }

        /// <summary>
        /// 设置模块与模块之间的依赖关系
        /// </summary>
        private void SetDependencies()
        {
            foreach (var moduleInfo in _modules)
            {
                foreach (var referencedAssemblyName in moduleInfo.Assembly.GetReferencedAssemblies())
                {
                    var referencedAssembly = Assembly.Load(referencedAssemblyName);
                    var dependedModuleList = _modules.Where(m => m.Assembly == referencedAssembly).ToList();
                    if (dependedModuleList.Count > 0)
                    {
                        moduleInfo.Dependencies.AddRange(dependedModuleList);
                    }
                }
                
                foreach (var dependedModuleType in BaseModule.FindDependedModuleTypes(moduleInfo.Type))
                {
                    var dependedModuleInfo = _modules.FirstOrDefault(m => m.Type == dependedModuleType);
                    if (dependedModuleInfo == null)
                    {
                        throw new TongTongMallException("没有找到该模块：" + dependedModuleType.AssemblyQualifiedName + " 与之关联的： " + moduleInfo.Type.AssemblyQualifiedName);
                    }

                    if ((moduleInfo.Dependencies.FirstOrDefault(dm => dm.Type == dependedModuleType) == null))
                    {
                        moduleInfo.Dependencies.Add(dependedModuleInfo);
                    }
                }
            }
        }
        /// <summary>
        /// 增加依赖关系程序集
        /// </summary>
        /// <param name="allModules"></param>
        /// <returns></returns>
        private static ICollection<Type> AddMissingDependedModules(ICollection<Type> allModules)
        {
            var initialModules = allModules.ToList();
            foreach (var module in initialModules)
            {
                FillDependedModules(module, allModules);
            }

            return allModules;
        }

        /// <summary>
        /// 填充依赖关系到对应的每一个活跃的程序集
        /// </summary>
        /// <param name="module"></param>
        /// <param name="allModules"></param>
        private static void FillDependedModules(Type module, ICollection<Type> allModules)
        {
            foreach (var dependedModule in BaseModule.FindDependedModuleTypes(module))
            {
                if (!allModules.Contains(dependedModule))
                {
                    allModules.Add(dependedModule);
                    FillDependedModules(dependedModule, allModules);
                }
            }
        }

        /// <summary>
        /// 系统核心模块设置到排序第一位
        /// </summary>
        /// <param name="sortedModules"></param>
        private void EnsureKernelModuleToBeFirst(List<ModuleInfo> sortedModules)
        {
            var kernelModuleIndex = sortedModules.FindIndex(m => m.Type == typeof(KernelModule));
            if (kernelModuleIndex > 0)
            {
                var kernelModule = sortedModules[kernelModuleIndex];
                sortedModules.RemoveAt(kernelModuleIndex);
                sortedModules.Insert(0, kernelModule);
            }
        }
    }
}
